// ============================================================================
// 定时任务调度器 - 管理定时微博爬取任务
// ============================================================================

import { logger } from '@roasmax/logger'
import { EventEmitter } from 'events'
import { ScheduledTaskParams, ScrapeTask } from '../../shared/types'
import { useEntityManager } from '../storage/data-source'
import { Account, Task } from '../storage/entities'
import { v4 as uuidv4 } from 'uuid'
import { creawlLatestWeiboByKeyword, searchTaskExecutor } from '../utils/searchTaskExecutor'

/**
 * 定时任务状态
 */
export interface SchedulerStatus {
  isRunning: boolean
  activeJobs: number
  totalJobs: number
  lastExecution?: Date
  nextExecution?: Date
  errors: string[]
}

/**
 * 定时任务配置
 */
export interface SchedulerConfig {
  enabled: boolean
  maxConcurrentJobs: number
  defaultInterval: number // 默认执行间隔（毫秒）
  retryAttempts: number
  retryDelay: number
  healthCheckInterval: number
}

/**
 * 定时任务调度器类
 */
export class TaskScheduler extends EventEmitter {
  private static instance: TaskScheduler
  private isRunning = false
  private scheduledJobs = new Map<string, NodeJS.Timeout>()
  private activeJobs = new Set<string>()
  private config: SchedulerConfig
  private healthCheckTimer?: NodeJS.Timeout

  constructor(
    config?: Partial<SchedulerConfig>
  ) {
    super()

    this.config = {
      enabled: true,
      maxConcurrentJobs: 3,
      defaultInterval: 30 * 60 * 1000, // 30分钟
      retryAttempts: 3,
      retryDelay: 5 * 60 * 1000, // 5分钟
      healthCheckInterval: 60 * 1000, // 1分钟
      ...config
    }
  }

  /**
   * 获取单例实例
   */
  static getInstance(
    config?: Partial<SchedulerConfig>
  ): TaskScheduler {
    if (!TaskScheduler.instance) {
      TaskScheduler.instance = new TaskScheduler(config)
    }
    return TaskScheduler.instance
  }

  /**
   * 启动调度器
   */
  async start(): Promise<void> {
    if (this.isRunning) {
      logger.warn('调度器已在运行中')
      return
    }

    if (!this.config.enabled) {
      logger.info('调度器已禁用，跳过启动')
      return
    }

    try {
      this.isRunning = true

      // 加载所有定时任务
      await this.loadScheduledTasks()

      // 启动健康检查
      this.startHealthCheck()

      logger.info('定时任务调度器启动成功', {
        maxConcurrentJobs: this.config.maxConcurrentJobs,
        defaultInterval: this.config.defaultInterval,
        scheduledJobsCount: this.scheduledJobs.size
      })

      this.emit('scheduler:started')
    } catch (error) {
      this.isRunning = false
      logger.error('启动调度器失败', error)
      throw error
    }
  }

  /**
   * 停止调度器
   */
  async stop(): Promise<void> {
    if (!this.isRunning) {
      logger.warn('调度器未在运行')
      return
    }

    try {
      this.isRunning = false

      // 清除所有定时器
      for (const [jobId, timer] of this.scheduledJobs) {
        clearTimeout(timer)
        logger.debug('清除定时任务', { jobId })
      }
      this.scheduledJobs.clear()

      // 停止健康检查
      if (this.healthCheckTimer) {
        clearInterval(this.healthCheckTimer)
        this.healthCheckTimer = undefined
      }

      // 等待活跃任务完成
      if (this.activeJobs.size > 0) {
        logger.info('等待活跃任务完成', { activeJobsCount: this.activeJobs.size })
        // 这里可以添加超时机制
      }

      logger.info('定时任务调度器已停止')
      this.emit('scheduler:stopped')
    } catch (error) {
      logger.error('停止调度器失败', error)
      throw error
    }
  }

  /**
   * 添加定时任务
   */
  async addScheduledTask(params: ScheduledTaskParams, accountId: string): Promise<string> {
    const taskId = uuidv4()

    const task: ScrapeTask = {
      id: taskId,
      type: 'scheduled',
      params,
      status: 'pending',
      accountId,
      createdAt: new Date(),
      priority: 1
    }

    // 保存到数据库
    logger.info('准备保存定时任务到数据库', { taskId, type: task.type, accountId })
    await useEntityManager(async m => {
      const taskRepo = m.getRepository(Task)
      const taskEntity = Task.fromScrapeTask(task)
      await taskRepo.save(taskEntity)
    })
    logger.info('定时任务已保存到数据库', { taskId })

    // 验证任务是否正确保存
    const savedTask = await useEntityManager(async m => {
      const taskRepo = m.getRepository(Task)
      return await taskRepo.findOne({ where: { id: taskId } })
    })
    if (savedTask) {
      logger.info('验证任务保存成功', { savedTaskId: savedTask.id, savedTaskType: savedTask.type })
    } else {
      logger.error('任务保存失败，无法从数据库中找到任务', { taskId })
    }

    // 如果调度器正在运行且任务启用，立即调度
    if (this.isRunning && params.enabled) {
      await this.scheduleTask(task)
    }

    logger.info('添加定时任务成功', {
      taskId,
      keywords: params.keywords,
      interval: params.interval,
      enabled: params.enabled
    })

    this.emit('task:scheduled', task)
    return taskId
  }

  /**
   * 更新定时任务
   */
  async updateScheduledTask(taskId: string, params: Partial<ScheduledTaskParams>): Promise<void> {
    const taskEntity = await useEntityManager(async m => {
      const taskRepo = m.getRepository(Task)
      return await taskRepo.findOne({ where: { id: taskId } })
    })

    if (!taskEntity || taskEntity.type !== 'scheduled') {
      throw new Error('定时任务不存在')
    }

    // 转换为 ScrapeTask 格式
    const task = taskEntity.toScrapeTask()

    // 更新参数
    const updatedParams = { ...task.params as ScheduledTaskParams, ...params }
    task.params = updatedParams

    // 保存到数据库
    await useEntityManager(async m => {
      const taskRepo = m.getRepository(Task)
      const updatedTaskEntity = Task.fromScrapeTask(task)
      await taskRepo.save(updatedTaskEntity)
    })

    // 重新调度任务
    if (this.isRunning) {
      await this.rescheduleTask(task)
    }

    logger.info('更新定时任务成功', { taskId, updatedParams })
    this.emit('task:updated', task)
  }

  /**
   * 删除定时任务
   */
  async removeScheduledTask(taskId: string): Promise<void> {
    // 取消调度
    if (this.scheduledJobs.has(taskId)) {
      clearTimeout(this.scheduledJobs.get(taskId)!)
      this.scheduledJobs.delete(taskId)
    }

    // 从数据库删除
    await useEntityManager(async m => {
      const taskRepo = m.getRepository(Task)
      await taskRepo.delete(taskId)
    })

    logger.info('删除定时任务成功', { taskId })
    this.emit('task:removed', taskId)
  }

  /**
   * 获取调度器状态
   */
  getStatus(): SchedulerStatus {
    // 由于这是同步方法，我们使用内存中的调度任务信息
    const status = {
      isRunning: this.isRunning,
      activeJobs: this.activeJobs.size,
      totalJobs: this.scheduledJobs.size,
      nextExecution: undefined,
      errors: [] // 这里可以添加错误收集机制
    }
    return status
  }

  /**
   * 立即执行定时任务
   */
  async executeTaskNow(taskId: string): Promise<void> {
    const taskEntity = await useEntityManager(async m => {
      const taskRepo = m.getRepository(Task)
      return await taskRepo.findOne({ where: { id: taskId } })
    })

    if (!taskEntity || taskEntity.type !== 'scheduled') {
      throw new Error('定时任务不存在')
    }

    const task = taskEntity.toScrapeTask()
    const params = task.params as ScheduledTaskParams
    if (!params.enabled) {
      throw new Error('任务已禁用')
    }

    await this.executeScheduledTask(task)
  }

  /**
   * 加载所有定时任务
   */
  private async loadScheduledTasks(): Promise<void> {
    const scheduledTasks = await useEntityManager(async m => {
      const taskRepo = m.getRepository(Task)
      const taskEntities = await taskRepo.find({ where: { type: 'scheduled' } })
      return taskEntities.map(entity => entity.toScrapeTask())
    })

    logger.info('加载定时任务', { count: scheduledTasks.length })

    for (const task of scheduledTasks) {
      const params = task.params as ScheduledTaskParams
      if (params.enabled) {
        await this.scheduleTask(task)
      }
    }
  }

  /**
   * 调度单个任务
   */
  private async scheduleTask(task: ScrapeTask): Promise<void> {
    const params = task.params as ScheduledTaskParams

    // 计算下次执行时间
    const now = new Date()
    const nextExecution = new Date(now.getTime() + params.interval)

    // 更新任务状态和下次执行时间
    task.status = 'scheduled'
    params.nextExecution = nextExecution

    await useEntityManager(async m => {
      const taskRepo = m.getRepository(Task)
      const taskEntity = Task.fromScrapeTask(task)
      await taskRepo.save(taskEntity)
    })

    // 设置定时器
    const timer = setTimeout(async () => {
      await this.executeScheduledTask(task)
    }, params.interval)

    this.scheduledJobs.set(task.id, timer)
  }

  /**
   * 重新调度任务
   */
  private async rescheduleTask(task: ScrapeTask): Promise<void> {
    // 取消现有调度
    if (this.scheduledJobs.has(task.id)) {
      clearTimeout(this.scheduledJobs.get(task.id)!)
      this.scheduledJobs.delete(task.id)
    }

    // 重新调度
    const params = task.params as ScheduledTaskParams
    if (params.enabled) {
      await this.scheduleTask(task)
    }
  }

  /**
   * 执行定时任务
   */
  private async executeScheduledTask(task: ScrapeTask): Promise<void> {
    const params = task.params as ScheduledTaskParams

    // 检查并发限制
    if (this.activeJobs.size >= this.config.maxConcurrentJobs) {
      logger.warn('达到最大并发限制，跳过任务执行', {
        taskId: task.id,
        activeJobs: this.activeJobs.size,
        maxConcurrentJobs: this.config.maxConcurrentJobs
      })

      // 重新调度到下一个时间点
      await this.scheduleTask(task)
      return
    }

    this.activeJobs.add(task.id)

    try {
      logger.info('开始执行定时任务')

      // 更新任务状态为运行中和最后执行时间
      task.status = 'running'
      params.lastExecuted = new Date()
      await useEntityManager(async m => {
        const taskRepo = m.getRepository(Task)
        const taskEntity = Task.fromScrapeTask(task)
        await taskRepo.save(taskEntity)
      })

      // 为每个关键字创建搜索任务
      for (const keyword of params.keywords) {
        if (!this.isRunning) {
          logger.info('调度器已停止，中断任务执行')
          break
        }

        try {
          await this.executeKeywordSearch(keyword, task, params)

          // 关键字间添加延迟
          await new Promise(resolve => setTimeout(resolve, 2000))
        } catch (error) {
          logger.error('关键字搜索失败', { keyword, error })
        }
      }

      logger.info('定时任务执行完成', { taskId: task.id })
      this.emit('task:completed', task)

    } catch (error) {
      logger.error('执行定时任务失败', { taskId: task.id, error })
      this.emit('task:failed', task, error)
    } finally {
      this.activeJobs.delete(task.id)

      // 重新调度下次执行
      if (this.isRunning && params.enabled) {
        // 任务执行完成后，重新调度会将状态设置为 scheduled
        await this.scheduleTask(task)
      } else {
        // 如果不重新调度，将状态设置为 completed
        task.status = 'completed'
        await useEntityManager(async m => {
          const taskRepo = m.getRepository(Task)
          const taskEntity = Task.fromScrapeTask(task)
          await taskRepo.save(taskEntity)
        })
      }
    }
  }

  async createTask(taskData: Omit<ScrapeTask, 'id' | 'createdAt'>): Promise<ScrapeTask> {
    const task: ScrapeTask = {
      id: uuidv4(),
      ...taskData,
      createdAt: new Date()
    }

    await useEntityManager(async m => {
      const taskRepo = m.getRepository(Task)
      const taskEntity = Task.fromScrapeTask(task)
      await taskRepo.save(taskEntity)
    })
    logger.info('任务创建成功', { taskId: task.id })

    return task
  }
  /**
   * 执行关键字搜索
   */
  private async executeKeywordSearch(
    keyword: string,
    parentTask: ScrapeTask,
    params: ScheduledTaskParams
  ): Promise<void> {
    const account = await useEntityManager(async m => {
      return m.findOne(Account, { where: { id: parseInt(parentTask.accountId) } })
    })
    if (!account) throw new Error(`not found account`)
    const cookiesArray = typeof account.cookies === 'string'
      ? JSON.parse(account.cookies)
      : account.cookies

    const cookies = cookiesArray.map((cookie: any) => ({
      name: cookie.name,
      value: cookie.value,
      domain: cookie.domain,
      path: cookie.path
    }))

    const cookieString = cookies.map((cookie: any) =>
      `${cookie.name}=${cookie.value}`
    ).join('; ')
    // 执行搜索任务
    return new Promise(async (resolve, reject) => {
      const subscription = await searchTaskExecutor(keyword, cookieString)
      if (subscription) {
        subscription.subscribe({
          next: (result) => console.log(`处理完成: ${JSON.stringify(result)}`),
          error: (err) => reject(err),
          complete: () => {
            resolve()
          }
        });
      }
    })

  }

  /**
   * 启动健康检查
   */
  private startHealthCheck(): void {
    this.healthCheckTimer = setInterval(() => {
      this.performHealthCheck()
    }, this.config.healthCheckInterval)
  }

  /**
   * 执行健康检查
   */
  private performHealthCheck(): void {
    try {
      const status = this.getStatus()

      logger.debug('调度器健康检查', {
        isRunning: status.isRunning,
        activeJobs: status.activeJobs,
        totalJobs: status.totalJobs,
        nextExecution: status.nextExecution?.toISOString()
      })

      this.emit('scheduler:health-check', status)
    } catch (error) {
      logger.error('健康检查失败', error)
    }
  }
}

/**
 * 全局调度器实例
 */
export let scheduler: TaskScheduler | null = null

/**
 * 初始化调度器
 */
export function initializeScheduler(
  config?: Partial<SchedulerConfig>
): TaskScheduler {
  scheduler = TaskScheduler.getInstance(config)
  return scheduler
}

/**
 * 获取调度器实例
 */
export function getScheduler(): TaskScheduler {
  if (!scheduler) {
    throw new Error('调度器未初始化，请先调用 initializeScheduler')
  }
  return scheduler
}
